/**   
* @Title: AbstractThread.java
* @Package org.xaoyaoyao.spider.download
* @Description: TODO
* @author xaoyaoyao
* @date Jan 25, 2019 1:24:55 PM
* @version V1.0   
*/
package org.xaoyaoyao.spider.download;

import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.xaoyaoyao.spider.downloader.HttpDownloader;
import org.xaoyaoyao.spider.dto.DownloadFileDto;
import org.xaoyaoyao.spider.entity.SpiderTask;
import org.xaoyaoyao.spider.enums.SeedEnum;
import org.xaoyaoyao.spider.properties.SpiderConfiguration;
import org.xaoyaoyao.spider.redis.RedisService;
import org.xaoyaoyao.spider.util.Constants;
import org.xaoyaoyao.spider.util.ContextLoader;
import org.xaoyaoyao.spider.util.StopSignalReceiver;

import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName: AbstractThread
 * @Description: TODO
 * @author xaoyaoyao
 * @date Jan 25, 2019 1:24:55 PM
 * 
 */
@Slf4j
public abstract class AbstractThread implements Runnable {

	private RedisService redisService;

	private SpiderConfiguration spiderConfiguration;

	private long time = 30000;

	public AbstractThread(RedisService redisService) {
		Assert.notNull(redisService, "RedisService cannot be null.");
		this.redisService = redisService;
		this.spiderConfiguration = ContextLoader.getBean(SpiderConfiguration.class);
		Assert.notNull(spiderConfiguration, "SpiderConfiguration cannot be null.");
	}

	@Override
	public void run() {
		log.error(">>>>>>>> 开始执行下载任务...");
		this.time = spiderConfiguration.getDownloadInterval() <= 5 ? time : spiderConfiguration.getDownloadInterval() * time;
		while (!isExit()) {
			SpiderTask task = null;
			try {
				task = getGrabTask();
				if (null == task) {
					Thread.sleep(time);// 30s
					continue;
				}
				String url = task.getUrl(), parameters = task.getParameters(), requestMethod = task.getRequestMethod(), headers = task.getHeaderParams(), ua = null, cookie = null;
				Map<String, Object> headerParams = getData(headers);
				Map<String, Object> params = getData(parameters);
				String htmlTxt = HttpDownloader.builder().url(url).requestMethod(requestMethod).params(params).headerParams(headerParams).ua(ua).cookie(cookie).build().download();
				log.debug(">>>>>>>> htmlTxt >> {}", htmlTxt);
				// 提交任务
				submitResult(task, htmlTxt);
			} catch (Exception e) {
				log.error(">>>>>>>> Check Thread Exception!", e);
				// 提交任务
				submitResult(task, null);
			}
		}
		if (isExit()) {
			log.error(">>>>>>>> 关闭任务！！！");
		}
	}

	@SuppressWarnings("unchecked")
	private Map<String, Object> getData(String parameters) {
		Map<String, Object> data = null;
		if (StringUtils.isNoneBlank(parameters)) {
			try {
				data = JSON.parseObject(parameters.toString(), Map.class);
			} catch (Exception e) {
				log.error(">>>>>>>> headers >> {}", parameters);
				log.error(e.getMessage(), e);
			}
		}
		return data;
	}

	private void submitResult(SpiderTask task, String htmlTxt) {
		// 提交任务，标记已处理完
		boolean result = submitTxt(task, htmlTxt);
		SeedEnum seedEnum = result ? SeedEnum.SUCCESS : SeedEnum.ERROR;
		SpiderTask spiderTask = new SpiderTask();
		spiderTask.setId(task.getId());
		spiderTask.setStatus(seedEnum.getCode());
		submitTaskResult(task);
	}

	/**
	 * @Title: submitTaskResult
	 * @Description: 处理任务结果（如更新状态等）
	 * @param task
	 * @return void
	 */
	public abstract void submitTaskResult(SpiderTask task);

	private boolean submitTxt(SpiderTask task, String htmlTxt) {
		if (StringUtils.isNoneBlank(htmlTxt)) {
			DownloadFileDto dto = new DownloadFileDto();
			dto.setDomain(task.getDomain());
			dto.setHtmlTxt(htmlTxt);
			dto.setTaskId(task.getId());
			redisService.lpush(Constants.SPIDER_PARSER_KEYS, dto.toString());
			return true;
		}
		return false;
	}

	private SpiderTask getGrabTask() {
		try {
			// 获取任务，可从redis获取任务
			String json = redisService.rpop(Constants.SPIDER_TASK_KEYS);
			log.debug(">>>>>>>> SpiderTask >> {}", json);
			if (StringUtils.isNotBlank(json)) {
				return SpiderTask.parse(json);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	private boolean isExit() {
		return StopSignalReceiver.isReceived();
	}
}
